﻿/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#define _CRT_SECURE_NO_WARNINGS
//! [Quoting ModelView Tutorial]
// mymodel.cpp
#include "mymodel.h"
#include <QtWidgets>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

int getNCol(char* buf, int len,int * nRow)
{
    int n = 0;
    int i = 0;
    *nRow = 0;
    for (; *buf != '\r' && *buf != '\n' && i < len; buf++) {
        if (*buf == ',') {
            n++;
        }
    }
    if (i < len) {
        n++;
    }
    for (; *buf && (*buf == '\r' || *buf == '\n'); buf++);


    for (; *buf; buf++) {
        if (*buf == '\r'|| *buf == '\n') {
            (*nRow)++;
            if (*(buf + 1) == '\r' || *(buf + 1) == '\n') {
                buf++;
            }
        }
    }
    if (*(buf - 1) != '\r' && *(buf - 1) != '\n')
    {
        (*nRow)++;
    }

    return n;
}

char* getNColStr(char* buf, char** pColStr, int n) {
    *pColStr = buf;
    for (int i = 0; *buf != '\r' && *buf != '\n' && i < n; buf++) {
        if (*buf == ',') {
            i++;
            *buf = 0;
            pColStr++;
            *pColStr = buf + 1;
        }
    }
    *buf = 0;
    buf++;
    if (*buf && *buf != '\r' && *buf != '\n') {
        return buf;
    }
    for (; *buf && (*buf == '\r' || *buf == '\n'); buf++);
    return buf;
}




int getData(char* pData, struct TIME_S* ps, double* pd, int nCol, int nRow)
{
    char* p = pData;
    int nrow = 0;
    for (;*p;nrow++) {
        int ncol = 0;
        ps++;
        double t = ps->dt=  atof(p);
        ps->hour = t / 3600;
        ps->min = int((t - ps->hour * 3600) / 60);
        ps->sec = int((t - ps->hour * 3600 - ps->min * 60));
        ps->msec = (t - (ps->hour * 3600 + ps->min * 60 + ps->sec)) * 1000;

        ncol++;
        for (; ncol < nCol; ncol++) {
            for (; *p != ',' && *p; p++);
            if (*p == ',') {
                p++;
                *pd = atof(p);
                pd++;
            }
        }
        //跳过最后的数字
        for (; *p && !(*p == '\r' || *p == '\n'); p++);
        //跳过回车换行
        for (; *p && (*p == '\r' || *p == '\n'); p++);
    }

    return 0;
}

int MyModel::openfile(char * fn)
{
    FILE* fp = fopen(fn, "rb");
    if (!fp) {
        printf("can't open %s", fn);
        return -2;
    }

    fseek(fp, 0, SEEK_END);
     int len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    char* buf = new char[len + 1];
    fread(buf, 1, len, fp);
    buf[len] = 0;

    nCol = getNCol(buf, len ,&nRow);
    pColName = new char* [nCol];
    char* pData = getNColStr(buf, pColName, nCol);

    ps = new struct TIME_S[nRow+1];
    memset(ps, 0, sizeof(struct TIME_S) * (nRow + 1));
    pd = new double[nCol * (nRow+1)];
    getData(pData, ps, pd, nCol, nRow);

#if 0
    struct TIME_S * pst = ps;
    double* p = pd;
    for (int i = 0; i < nRow; i++,pst++) {
        printf("%d-%02d-%02d %02d:%02d:%02d+%02d:00 ", pst->year, pst->month, pst->day, pst->hour, pst->min, pst->sec, pst->timezone);
            for(int j = 1; j < nCol; j++, p++) {
                printf(" %.4lf", *p);
            }
        printf("\n");
    }
#endif

    fclose(fp);
    return 0;
}


#define SAFE_DELETE(x) if(x){ delete []x;}
MyModel::MyModel(QObject *parent)
    :QAbstractTableModel(parent)
{
    buf = NULL;
    pColName = NULL;
    ps = NULL;
    pd = NULL;
    nRow = 0;
    nCol = 0;
}

MyModel::~MyModel()
{
    SAFE_DELETE(buf);
    SAFE_DELETE(pColName);
    SAFE_DELETE(ps);
    SAFE_DELETE(pd);
}


int MyModel::rowCount(const QModelIndex & /*parent*/) const
{
    return nRow;
}

int MyModel::columnCount(const QModelIndex & /*parent*/) const
{
    return nCol;
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        if(nRow){
            if (index.column() == 0) {
                struct TIME_S* pst = ps + index.row();
#if 0
                char buf[128];
                sprintf(buf, "%02d:%02d:%02d.%03d", pst->hour, pst->min, pst->sec, pst->msec);
                return QString(buf);
#else
                return pst->dt;
#endif
            }
            else if (index.column() < nCol) {
                return QString::number(pd[(nCol - 1) * index.row() + (index.column() - 1)], 'f', 4);
            }
        }
    }
    return QVariant();
}

QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            return this->getColName(section);
        }
        else {
            return section;
        }
    }
    return QVariant();
}


Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
{
    return QAbstractTableModel::flags(index);
}


int MyModel::saveVibrateCSVFile(QString fileName, int peroid)
{
    if (nRow < 2) {
        return -1;
    }

    std::string stdFileStr = fileName.toStdString();
    FILE* fp = fopen(stdFileStr.c_str(), "wt");
    if (fp == NULL) {
        return -2;
    }
    fprintf(fp, "%s", pColName[0]);
    for (int i = 1; i < nCol; i++) {
        fprintf(fp, ",%s", pColName[i]);
    }

    int nDataCol = nCol - 1;

    int dt = (ps + 1)->t - ps->t;
    int dperiod = peroid * 60;
    int nratio = dperiod / dt;
    struct TIME_S * psn = new struct TIME_S[nRow];
    double * pdn = new double[nRow * nDataCol];
    double * pmax = new double[nDataCol * 2];
    double* pmin = pmax + nDataCol;

    double* p = pd;
    TIME_S* psc = ps;
    TIME_S* psd = psn;
    
    double* pa = pmax;
    double* pi = pmin;

    *psd = *psc;
    psc++;
    int nRowNewTable = 0;
    //the first row
    int nRowInCur = 0;
    for (int j = 0; j < nDataCol; j++,pa++,pi++,p++) {
        *pa = *pi = *p;
        nRowInCur = 1;
    }
    double* pdd = pdn;
    for (int i = 1; i < nRow; i++, psc++) {
        pa = pmax;
        pi = pmin;
        bool assign = false;
        bool getminmax = true;
        if (psc->t - psd->t >= dperiod) {
            assign = true;
            if (nRowInCur == 1) {
                getminmax = true;
            }
            else {
                getminmax = false;
                nRowInCur = 1;
            }
            nRowNewTable++;
            fprintf(fp, "\n%d-%02d-%02d %02d:%02d:%02d+%02d:00", psd->year, psd->month, psd->day, psd->hour, psd->min, psd->sec, psd->timezone);
            psd++;
            *psd = *psc;
        }
        else {
            nRowInCur++;
        }

        for (int j = 0; j < nDataCol; j++,p++,pa++, pi++)
        {
               if (getminmax) {
                    if (*p > *pa) {
                        *pa = *p;
                    }
                    else if (*p < *pi) {
                        *pi = *p;
                    }
                }
               if (assign) {
                   *pdd = *(pa)-*(pi);
                   fprintf(fp, ",%.4lf", *pdd);
                   *pa = *pi = *p;
                   pdd++;
               }
        }
    }
    if (nRowInCur > 1) {
        nRowNewTable++;
        fprintf(fp, "\n%d-%02d-%02d %02d:%02d:%02d+%02d:00", psd->year, psd->month, psd->day, psd->hour, psd->min, psd->sec, psd->timezone);
        pa = pmax;
        pi = pmin;
        for (int j = 0; j < nDataCol; j++, pa++, pi++)
        {
             *pdd = *(pa)-*(pi);
              fprintf(fp, ",%.4lf", *pdd);
              pdd++;
        }
    }

    fclose(fp);

    int period_to[] = { 5,10,20,40,60,100,0 };
    for (int i = 0; i < nDataCol; i++) {
    //for (int i = 0; i < 1; i++) {
        QFileInfo fileinfo(fileName);
        QString  file_name = fileinfo.baseName() + "_" + pColName[i + 1] + ".csv";
        QDir dir(fileinfo.canonicalPath());
        QString subDataPath = dir.absoluteFilePath(file_name);
        std::string subFileName = subDataPath.toStdString();
        save_mean_max_min_stdvar_in_t(subFileName.c_str(), pColName, psn, i, pdn, nRow,nDataCol, nRowNewTable, period_to, 6);
    }
    delete[]psn;
    delete[]pdn;
    delete[]pmax;

    return 0;
}

int MyModel::getMA(double* pData, int nColDataGap, int nDataCol, int nDataRow, int nthCol, int peroid, double* pMAStart)
{
    double MA = 0;
    pData += nthCol;
    double * pd = pData;
    double* p = pd;
    double* pMax = pMAStart + nDataRow;
    double* pMin = pMax + nDataRow;
    double* pStdvar = pMin + nDataRow;
    double min, max, stdvar;
    min = max = *pd;
    int i = 1;
    double* pMA = pMAStart;
    for (; i <= peroid && i <= nDataRow; i++, pd += nDataCol, pMA++, pMax++, pMin++, pStdvar++) {
        MA += *pd;
        *pMA = MA / i;
        if (*pd > max)
            max = *pd;
        else  if (*pd < min)
            min = *pd;
        *pMax = max;
        *pMin = min;
        if(i<peroid)
          *pStdvar = 0;//to do :get the stdvar
        else {
            double* pt = pData;
            double meanval = *pMA;
            double total = 0;
            for (int j = 0; j < peroid; j++, pt++)
            {
                double t = (*pt - meanval);
                total += (t * t);
            }
            *pStdvar = sqrt(total / peroid);
        }
    }
    for (; i <= nDataRow; i++, pd+=nDataCol,p+=nDataCol,pMA++,pMax++,pMin++,pStdvar++) {
        MA += *pd;
        MA -= *p;
        *pMA = MA / peroid;
        
        double* pm = p+nDataCol;
        min = max = *pm;
        for (int j = 0; j < peroid; j++,pm +=nDataCol) {
            if (min > *pm) {
                min = *pm;
            }
            else if (max < *pm) {
                max = *pm;
            }
        }
        *pMax = max;
        *pMin = min;

        double* pt = p+nDataCol;
        double meanval = *pMA;
        double total = 0;
        for (int j = 0; j < peroid; j++, pt++)
        {
            double t = (*pt - meanval);
            total += (t * t);
        }
        *pStdvar = sqrt(total / peroid);
    }

    return 0;
}

char* MyModel::getColName(int i) const
{
    if (i < nCol) {
        return pColName[i];
    }
    else
        return (char *)"index";
}

int MyModel::save_mean_max_min_stdvar_in_t(const char* fileName, char** pColName, TIME_S* pt, int nthCol, double* pd, int nColDataGap, int nDataCol, int nDataRow, int * peroid_to, int nperoid_to)
{
    FILE* fp = fopen(fileName, "wt");
    if (!fp) {
       return -1;
    }
    fprintf(fp, "%s,", pColName[0]);
    char* pName = pColName[nthCol + 1];
    fprintf(fp, "%s", pName);
    double* pnd = new double[nDataRow * nperoid_to*4];//ma max min stdvar
    double* p = pnd;
    for (; *peroid_to; peroid_to++,p+=(nDataRow*4)) {
        int t = *peroid_to;
        fprintf(fp, ",MA%d,MAX%d,MIN%d,STDV%d", t,t,t,t);
        getMA(pd, nColDataGap,nDataCol, nDataRow, nthCol, *peroid_to, p);
    }
    double* pdt = pd + nthCol;
    double* pndt = pnd;
    for (int i = 0; i < nDataRow; i++,pdt+=nDataCol,pndt++,pt++) {
        fprintf(fp,"\n%d-%02d-%02d %02d:%02d:%02d+%02d:00", pt->year, pt->month, pt->day, pt->hour, pt->min, pt->sec, pt->timezone);
        fprintf(fp, ",%.4lf", *pdt);
        p = pndt;
        for (int j = 0; j < nperoid_to*4; j++ , p+=(nDataRow)){
            fprintf(fp, ",%.4lf ", *p);
        }
    }

    fclose(fp);

    return 0;
}

void TIME_S::get_time_t()
{
    struct tm nowtime;

    nowtime.tm_sec = sec;/* Seconds.[0-60](1 leap second)*/

    nowtime.tm_min = min;/* Minutes.[0-59] */

    nowtime.tm_hour = hour;/* Hours. [0-23] */

    nowtime.tm_mday = day;/* Day.[1-31] */

    nowtime.tm_mon = month-1;/* Month.[0-11]*/

    nowtime.tm_year = year - 1900;/* Year- 1900.*/

    nowtime.tm_isdst = -1;/*DST.[-1/0/1]*/

    t = mktime(&nowtime);
}
